/*
* Snakes on a Payload
* Copyright (C) 2011 CORE Security Technologies
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
* 
* Authors:
* 2011/09/11 - Pedro Varangot (pvarangot@)
* 2011/09/11 - Fernando Russ (fruss@)
*/

#include <stddef.h>

typedef unsigned int relentry_type;
typedef unsigned long relentry_offset;

#define RELENTRY_TYPE_END 0
#define RELENTRY_TYPE_REBASE 1
#define RELENTRY_TYPE_JMPSLOT 2
#define RELENTRY_TYPE_LOADLIB 3

#define PACKED __attribute__ ((__packed__))

typedef union PACKED {
    struct PACKED {
      relentry_type type;
      relentry_offset offset;
    } rebase_reloc;
    struct PACKED {
      relentry_type type;
      relentry_offset offset;
      char symbol_name[128];
    } jmpslot_reloc;
    struct PACKED {
      relentry_type type;
    } end;
} reloc_entry;

int __attribute__ ((section (".rebase"), visibility("hidden")))
    rebase_relocs(void(*base)(),
       int(*entrypoint)(),
       reloc_entry *relocs,
       void *(*dlopen)(const char *, int),
       void *(*dlsym)(void *, const char *)
    )
{
    unsigned long idx = 0;
    void *handle = NULL;
    size_t *relocation;

    while( relocs[idx].end.type != RELENTRY_TYPE_END )
    {
        relocation = (size_t*)(relocs[idx].rebase_reloc.offset + (size_t)base);
        switch(relocs[idx].end.type) {
            case RELENTRY_TYPE_REBASE:
              *relocation = *relocation + (size_t)base;
              break;
            
            case RELENTRY_TYPE_JMPSLOT:
              *relocation = (size_t)dlsym(handle, relocs[idx].jmpslot_reloc.symbol_name);
              break;
            
            case RELENTRY_TYPE_LOADLIB:
              handle = dlopen(relocs[idx].jmpslot_reloc.symbol_name, 2);
              break;
            
        }
        idx ++;
    }
    
    return entrypoint();
}

